package openGl.camera;

import android.content.Context;
import android.graphics.Point;
import android.graphics.SurfaceTexture;
import android.opengl.GLES11Ext;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.opengl.Matrix;
import android.util.Log;

import java.nio.FloatBuffer;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import camera.OpenGl.utils.ByteBufferUtils;

/**
 * Created by Administrator on 2017/12/29.
 */

public class CameraRender implements GLSurfaceView.Renderer {
    private int cameraId=0;
    private String Tag="CameraRender";
    private  Context mContext;
    private KitkatCamera camera;
    private SurfaceTexture mSurfaceTexure;
    private CameraShaderProgram cameraShaderProgram;
    private CameraSurfaceView cameraSurfaceView;
    private FloatBuffer vertexDataBuffer;
    private float[] projectMatrix=new float[16];
    //每行前两个值为顶点坐标，后两个为纹理坐标
    private static final float[] vertexData = {
            1f,  1f, 1f,  1f,
            -1f,  1f,  0f,  1f,
            -1f, -1f,  0f,  0f,
            1f,  1f,  1f,  1f,
            -1f, -1f,  0f,  0f,
            1f, -1f,  1f,  0f
    };
    private int textureID;
    //顶点坐标
    private float pos[] = {
            -1.0f,  1.0f,
            -1.0f, -1.0f,
            1.0f, 1.0f,
            1.0f,  -1.0f,
    };

    //纹理坐标
    private float[] coord={
            0.0f, 0.0f,
            0.0f,  1.0f,
            1.0f,  0.0f,
            1.0f, 1.0f,
    };

    public CameraRender(Context context,CameraSurfaceView cameraSurfaceView) {
        this.mContext=context;
        this.cameraSurfaceView=cameraSurfaceView;
        camera=new KitkatCamera();
        vertexDataBuffer= ByteBufferUtils.makeFloteByteBuffer(vertexData);
    }
    private void  bindData(){
        GLES20.glEnableVertexAttribArray(cameraShaderProgram.vPosition);
        vertexDataBuffer.position(0);
        GLES20.glVertexAttribPointer(cameraShaderProgram.vPosition,2,
                GLES20.GL_FLOAT,false,16,vertexDataBuffer);
        GLES20.glEnableVertexAttribArray(cameraShaderProgram.inputTextureCoordinate);
        vertexDataBuffer.position(2);
        GLES20.glVertexAttribPointer(cameraShaderProgram.inputTextureCoordinate,2,
                GLES20.GL_FLOAT,false,16,vertexDataBuffer);
    }

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        Log.e(Tag,"onSurfaceCreated");
        cameraShaderProgram=new CameraShaderProgram(mContext);
        textureID = createTextureID();
        mSurfaceTexure=new SurfaceTexture(textureID);
        bindData();
        camera.open(cameraId);
        Point point=camera.getPreviewSize();
        //setDataSize(point.x,point.y);
        camera.setPreviewTexture(mSurfaceTexure);
        mSurfaceTexure.setOnFrameAvailableListener(new SurfaceTexture.OnFrameAvailableListener() {
            @Override
            public void onFrameAvailable(SurfaceTexture surfaceTexture) {
               cameraSurfaceView.requestRender();
            }
        });
        camera.preview();
        
    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
       // setViewSize(width,height);
        GLES20.glViewport(0,0,width,height);
        Matrix.orthoM(projectMatrix,0,-1,1,-1,1,-1,1);
    }

    @Override
    public void onDrawFrame(GL10 gl) {
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
        if (mSurfaceTexure!=null){
            mSurfaceTexure.updateTexImage();
        }
        cameraShaderProgram.useProgram();
       // mSurfaceTexure.getTransformMatrix(projectMatrix);
        GLES20.glUniformMatrix4fv(cameraShaderProgram.vMatrix,1,false,projectMatrix,0);
        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
        GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,textureID);
        GLES20.glUniform1i(cameraShaderProgram.s_texture,0);
        GLES20.glDrawArrays(GLES20.GL_TRIANGLES,0,3);
        GLES20.glDrawArrays(GLES20.GL_TRIANGLES,3,3);
    }

    /**
     * 产生一个纹理
     * @return
     */
    private int createTextureID(){
        int[] texture = new int[1];
        GLES20.glGenTextures(1, texture, 0);
        GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, texture[0]);
        GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
                GL10.GL_TEXTURE_MIN_FILTER,GL10.GL_LINEAR);
        GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
                GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
        GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
                GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE);
        GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
                GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE);
        return texture[0];
    }
    private float[] matrix=new float[16];
    private int width,height;
    private int dataWidth,dataHeight;
    public void setViewSize(int width,int height){
        this.width=width;
        this.height=height;
        calculateMatrix();
    }
    public void setDataSize(int dataWidth,int dataHeight){
        this.dataWidth=dataWidth;
        this.dataHeight=dataHeight;
        calculateMatrix();
    }

    private void calculateMatrix(){
        getShowMatrix(matrix,this.dataWidth,this.dataHeight,this.width,this.height);
        if(cameraId==1){
         flip(projectMatrix,true,false);
            rotate(projectMatrix,90);
        }else{
            rotate(projectMatrix,270);
        }
    }
    public static void getShowMatrix(float[] matrix,int imgWidth,int imgHeight,int viewWidth,int
            viewHeight){
        if(imgHeight>0&&imgWidth>0&&viewWidth>0&&viewHeight>0){
            float sWhView=(float)viewWidth/viewHeight;
            float sWhImg=(float)imgWidth/imgHeight;
            float[] projection=new float[16];
            float[] camera=new float[16];
            if(sWhImg>sWhView){
                Matrix.orthoM(projection,0,-sWhView/sWhImg,sWhView/sWhImg,-1,1,1,3);
            }else{
                Matrix.orthoM(projection,0,-1,1,-sWhImg/sWhView,sWhImg/sWhView,1,3);
            }
            Matrix.setLookAtM(camera,0,0,0,1,0,0,0,0,1,0);
            Matrix.multiplyMM(matrix,0,projection,0,camera,0);
        }
    }
    public static float[] rotate(float[] m,float angle){
        Matrix.rotateM(m,0,angle,0,0,1);
        return m;
    }

    public static float[] flip(float[] m,boolean x,boolean y){
        if(x||y){
            Matrix.scaleM(m,0,x?-1:1,y?-1:1,1);
        }
        return m;
    }

}
